using System.Collections;
using Slaks.DocumentSerialization.Document;
using Slaks.Graphs;
using Slaks.Graphs.Comparators;
using Slaks.Graphs.GraphBuilder;

namespace Slaks.GraphExtensions.GraphBuilder
{
	public class SlaksBuilder
	{
		public void RemoveInfrequentVerticesInTemporalSuperGraph(SuperGraph temporalSuperGraph, int numberOfVerticesToLeave)
		{
			ICollection graphs = temporalSuperGraph.GetGraphs();

			foreach (Graph graph in graphs)
			{
				this.RemoveInfrequentVerticesInTemporalGraph(graph, numberOfVerticesToLeave);
			}
		}


		/// <summary>
		/// Removes the rest of infrequent vertices leaving at most (numberOfVerticesToLeave)
		/// Used for temporal graph for quering about existing vertices
		/// </summary>
		/// <param name="numberOfVerticesToLeave"></param>
		protected void RemoveInfrequentVerticesInTemporalGraph(Graph temporalGraph, int numberOfVerticesToLeave)
		{
			VertexList vertexList = temporalGraph.GetVertexList();
			Id2VertexMap id2VertexMapper = temporalGraph.GetId2VertexMap();
			if (numberOfVerticesToLeave <= 0) return;
			int totalCount = vertexList.Count;
			if (numberOfVerticesToLeave >= totalCount) return;
			//what is desired length of the vertex list

			temporalGraph.SortVertices(new FrequencyComparer());

			int currentIndex = numberOfVerticesToLeave;

			long idToRemove;
			while (vertexList.Count > numberOfVerticesToLeave)
			{
				idToRemove = vertexList[currentIndex].GetId();
				vertexList.RemoveAt(currentIndex);
				id2VertexMapper.Remove(idToRemove);
			}

		}

		/// <summary>
		/// Builds the temporal graph only with vertices
		/// </summary>
		/// <param name="document"></param>
		/// <returns></returns>
		protected SuperGraph BuildTemporalSuperGraph(Document document)
		{
			Vertex vertex;
			SuperGraph superGraph = new SuperGraph();
			Graph tempGraph = null;

			string sectionTypeString;
			//create temporal graph
			//iterate through nodes
			foreach (Node node in document.Nodes)
			{
				foreach (Section section in node.Sections)
				{
					sectionTypeString = section.GetSectionTypeString();
					//xml provides separate section for meta-description, but shenker algorithm treats meta-description as title
					if (sectionTypeString == "meta-description")
						sectionTypeString = "title";

					tempGraph = superGraph.GetGraphBySectionType(sectionTypeString);
					if (tempGraph == null)
					{
						tempGraph = new Graph();
						superGraph.AddGraph(tempGraph, sectionTypeString);
					}
					vertex = tempGraph.CreateAddVertex(node.Id);
					vertex.Frequency = section.TermFrequency;
				}
			}
			return superGraph;
		}

		/// <summary>
		/// Add edges between nodes
		/// </summary>
		/// <param name="document"></param>
		/// <param name="graph">graph to build</param>
		/// <param name="temporalGraph">temporal graph which hold only frequent nodes. it will be queried for them</param>
		/// <param name="currentVertex">the current node</param>
		/// <param name="nParameter">the n-distance parameter</param>
		/// <param name="nDistanceCount">current distance counter</param>
		/// <param name="sentence">current sentence</param>
		/// <param name="sectionType">section type</param>
		protected void AddRelations(Document document,
		                            Graph graph,
		                            Graph temporalGraph,
		                            Vertex currentVertex,
		                            int nParameter,
		                            int nDistanceCount,
		                            Sentence sentence,
		                            Section.SectionType sectionType,
		                            BuilderType builderType
			)
		{
			if (nDistanceCount > nParameter) return;
			Node node;
			long nextId;
			Vertex nextIdVertex;
			if (sentence.NextId >= 0)
			{
				//get the nextId.
				nextId = sentence.NextId;
				//we must check whether the nextId is in the list of frequent nodes.
				//if not then we must skip it.

				nextIdVertex = temporalGraph.GetVertex(nextId);

				node = document.GetNodeById(nextId);
				Section section = node.GetSectionByType(sectionType);
				if (section == null) return;
				Sentence nextSentence = section.GetSentence(sentence.Number, sentence.Place + 1);
				if (nextSentence == null) return;

				string sectionLabel;

				if (nextIdVertex != null) //the nextIdVertex is among frequent nodes
				{
					if (builderType == BuilderType.NDistanceRepresentationSlaks) sectionLabel = nDistanceCount.ToString();
					else if (builderType == BuilderType.NSimpleDistanceRepresentationSlaks) sectionLabel = "no";
					else sectionLabel = section.GetSectionTypeString();

					nextIdVertex = graph.CreateAddVertex(nextId);
					currentVertex.AddEdge(nextIdVertex, sectionLabel);

					AddRelations(document, graph, temporalGraph, currentVertex, nParameter, nDistanceCount + 1, nextSentence, sectionType, builderType);
				}
				else
				{
					//the nextIdVertex is not frequent, then we must skip it and find the frequent node.
					AddRelations(document, graph, temporalGraph, currentVertex, nParameter, nDistanceCount, nextSentence, sectionType, builderType);
				}
			}
			return;
		}

	}
}